package study.JavaAdvanced;

/**
 * date：2025.11.17
 * title：生产者消费者
 * author：fzy
 */


/*
 * 生产者消费者
 * 生产者生产资源，消费者消费资源，
 * object提供了等待呼喊方法
 * void wait():导致当前线程等待，直到另一个线程调用当前对象的notify()方法
 * void notify()：唤醒正在等待对象监视的单个线程
 * void notifyAll()：唤醒正在等待对象监视的所有线程
 */

    /*
    box类，存储资源
    producer类，生产资源 实现runnable类
    customer:消耗资源 实现runnable类
    测试类
     */
//思思又考考
//1.runnable类实现资源共享，共享的资源一定是box类，所以box类应该是实现runnable？？//错错的误误，实现了runable就是一个线程了
//那么box类该怎么办呢，怎么实现在外部实例
//2.生产者和消费者要对公共资源进行编辑，所以他们要作为两个线程对吧哈哈
//3.生产和消费应该不对等，体现这个测试，当没有资源的时候，消费者要等，知道生产者生产资源，emmmmmm.?-->所以在生产者消费的时候需要判断资源睡觉哦有没有吧哈啊哈
//没有的话就wait，直到消费者调用notify方法，emmmm，他们两个需要互相调用？这两个线程之间要互相交互?怎么搞？可以在主线程嘛，这样就没有什么意义了吧哈哈
//先写，比比这么多都没什么用哈哈哈哈哈哈啊哈哈
public class Java_10 {
    public static void main(String[] arg) {
//        PCManager.manager();
        Ai_PCManager.manager();
    }
}


class PCManager{
    static void manager(){
        Box b = new Box();
        Product p = new Product(b);
        Customer c= new Customer(b);
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);
        t1.start();
        t2.start();
    }
}

class Box{
    private final int maxCount = 10;
    private int count = 0;

    public void consumeCount(int consumeNum){
        this.count -= consumeNum;
        System.out.println("消耗了"+consumeNum+"单位,当前容量为"+this.count);
    }

    public void productCount(int productNum){
        this.count+= productNum;
        System.out.println("生产了"+productNum+"单位，当前容量为"+this.count);
    }


    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

class Product implements Runnable{
    private int productSpeed = 5;
    Box b;
    Product(Box b){
        this.b = b;
    }

    @Override
    public synchronized void run() {
        while (true){
            try {
                if(b.getCount()<10){
                    this.b.productCount(this.productSpeed);
                }else {
                    /**
                     * error
                     */
                    notify();
                    wait();
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

class Customer implements Runnable{

    private int customerSpeed = 1;
    Box b;
    Customer(Box b){
        this.b = b;
    }

    @Override
    public synchronized void run() {
        while (true){
            try {
                if(this.b.getCount()>5){
                    b.consumeCount(customerSpeed);
                }else if(this.b.getCount()<2){
                    wait();
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

//我写的，Ai说有三个错误
//1.锁对象错误，synchronized锁的各自的实例，只有锁同一个实例才能保证原子性
//2.wait，notify调用对象错误，wait和notify必须在持有锁的对象上
//3.未设置缓冲区，这个先不管
//下面是Ai写的,非常的优雅
//


class Ai_PCManager {
    static void manager() {
        Ai_Box b = new Ai_Box(); // 唯一共享缓冲区（锁对象）
        Ai_Product p = new Ai_Product(b);
        Ai_Customer c = new Ai_Customer(b);
        Thread t1 = new Thread(p, "生产者");
        Thread t2 = new Thread(c, "消费者");
        t1.start();
        t2.start();
    }

    public static void main(String[] args) {
        PCManager.manager(); // 启动测试
    }
}

class Ai_Box {
    private final int maxCount = 10; // 缓冲区上限
    private int count = 0; // 当前库存

    // 生产方法：必须同步（锁当前 Box 对象）
    public synchronized void productCount(int productNum) throws InterruptedException {
        // 1. 库存不足时，等待消费者消费（用 while 避免虚假唤醒）
        while (count + productNum > maxCount) {
            System.out.println(Thread.currentThread().getName() + "：缓冲区已满（当前" + count + "），等待消费...");
            wait(); // 释放 Box 锁，进入等待队列
        }
        // 2. 生产操作（原子性）
        count += productNum;
        System.out.println(Thread.currentThread().getName() + "：生产了" + productNum + "单位，当前容量为" + count);
        // 3. 生产后通知消费者（有数据了）
        notify();
    }

    // 消费方法：必须同步（锁当前 Box 对象）
    public synchronized void consumeCount(int consumeNum) throws InterruptedException {
        // 1. 库存不足时，等待生产者生产（用 while 避免虚假唤醒）
        while (count < consumeNum) {
            System.out.println(Thread.currentThread().getName() + "：缓冲区不足（当前" + count + "），等待生产...");
            wait(); // 释放 Box 锁，进入等待队列
        }
        // 2. 消费操作（原子性）
        count -= consumeNum;
        System.out.println(Thread.currentThread().getName() + "：消耗了" + consumeNum + "单位，当前容量为" + count);
        // 3. 消费后通知生产者（有空间了）
        notify();
    }
}

class Ai_Product implements Runnable {
    private final int productSpeed = 2; // 每次生产5个
    private final Ai_Box b;

    Ai_Product(Ai_Box b) {
        this.b = b;
    }

    @Override
    public void run() { // 无需加 synchronized（同步逻辑在 Box 内部）
        while (true) { // 无限生产
            try {
                b.productCount(productSpeed); // 调用 Box 的同步方法
                Thread.sleep(1000); // 生产间隔
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 保留中断状态
                break;
            }
        }
    }
}

class Ai_Customer implements Runnable {
    private final int customerSpeed = 7; // 每次消费1个
    private final Ai_Box b;

    Ai_Customer(Ai_Box b) {
        this.b = b;
    }

    @Override
    public void run() { // 无需加 synchronized（同步逻辑在 Box 内部）
        while (true) { // 无限消费
            try {
                b.consumeCount(customerSpeed); // 调用 Box 的同步方法
                Thread.sleep(1000); // 消费间隔
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 保留中断状态
                break;
            }
        }
    }
}

